﻿using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace Might.Infrastructure.DOM {

    public interface INotifyChange : INotifyPropertyChanged {
        event EventHandler Changed;

        /// <summary>
        /// Start multiple operation on single IDomNode
        /// </summary>
        void StartUpdate();

        /// <summary>
        /// Finish update on current IDomnode.
        /// </summary>
        void FinishUpdate();

        /// <summary> 
        /// Finish update on current IDomnode.
        /// </summary>
        /// <param name="exceptObj">Call source, that don't want to be notified about changes.</param>
        void FinishUpdate(object exceptObj);
    }

    /// <summary>
    /// A special-purpose node containing other nodes.
    /// </summary>
    public interface IDomNode : INotifyChange {

        /// <summary>
        /// Parent in logical tree dom
        /// </summary>
        IDomNode Parent { get; set; }

        ///<summary>
        /// Readonly property indicating, if given dom item is leaf or not.
        ///</summary>
        bool IsContainer { get; }

        // children

        /// <summary>
        /// Base function for retrieving group of IDomNodes. Every group is created in lazy fashion.
        /// </summary>
        /// <param name="groupName">Name of the containing group</param>
        /// <returns></returns>
        //IDomNodeCollection this[string groupName] { get; }
      
        //[Obsolete("Do not use, use indexer instead.")]
        IDomNodeCollection GetChildren(string groupName);

        //[Obsolete("Do not use, use (this[groupName] != null) instead.")]
        bool CanHasChildOfType(string groupName);

        /// <summary>
        /// Syntactic sugar for GetChildren(string groupName)[0]
        /// </summary>
        //[Obsolete("Do not use, use this[groupName][0] instead.")]
        IDomNode GetFirstChild(string groupName);

        /// <summary>
        /// Collection is not insertable to specific position.
        /// </summary>
        //[Obsolete("Do not use, use this[groupName].Add(child) instead.")]
        // use this for now
        void InsertChild(string groupName, IDomNode child);
        
        /// <summary>
        /// Remove specific child from given group.
        /// </summary>
        //[Obsolete("Do not use, use this[groupName].Remove(child) instead.")]
        void RemoveChild(string groupName, IDomNode child);

        /// <summary>
        /// Remove all children in a specific group. Group is not deleted.
        /// </summary>
        //[Obsolete("Do not use, use this[groupName].Clear() instead.")]
        void EmptyGroup(string groupName);

        /// <summary>
        /// Gets the group names.
        /// </summary>
        /// <returns></returns>
        string[] GetGroupNames();

        /// <summary>
        /// Remove all children in all groups. Groups are not deleted, just made empty.
        /// </summary>
        void ClearAllGroups();


        // references

        /// <summary>
        /// List of types, that derives from this domnode.
        /// </summary>
        List<IDomNode> DerivedTypes { get; }

        /// <summary>
        /// Inserts the reference.
        /// </summary>
        /// <param name="refName">Unique name of the reference.</param>
        /// <param name="reference">The reference.</param>
        void InsertReference( string refName , IDomReference reference );
        
        /// <summary> 
        /// References across DOM, used for items that are not logical childs.
        /// General graph.
        /// </summary>
        /// <param name="refName">Unique name of the reference.</param>
        /// <returns></returns>
        IDomReference GetReference( string refName );


        List<IDomReference> GetReferences();

        /// <summary>
        /// Removes the reference.
        /// </summary>
        /// <param name="refName">Unique name of the reference.</param>
        void RemoveReference( string refName );

        /// <summary>
        /// Removes the reference.
        /// </summary>
        /// <param name="reference">The reference for remove.</param>
        void RemoveReference( IDomReference reference );

        /// <summary>
        /// Removes all references.
        /// </summary>
        void RemoveAllReferences();

        /// <summary>
        /// Function is called when target of reference is deleted.
        /// </summary>
        /// <param name="node">The node.</param>
        void ReferenceDeleted( IDomNode node );

        /// <summary>
        /// Sets this node as reference for another node
        /// </summary>
        /// <param name="node">Node which refers on this node.</param>
        void SetAsReference( IDomNode node );

        /// <summary>
        /// Removes this node as references for another node.
        /// </summary>
        /// <param name="node">The which not refers for this node as reference now.</param>
        void RemoveAsReference( IDomNode node );
    }
}
